﻿namespace FsharpCad

open System
#if acad
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Geometry
#endif
#if zcad
open ZwSoft.ZwCAD.DatabaseServices
open ZwSoft.ZwCAD.EditorInput
open ZwSoft.ZwCAD.Geometry
#endif
/// 过滤器
type OpFilter =
    | EntityType of string // dxf 0
    | BlockName of string // dxf 2
    | LayerName of string // dxf 8
    | Visibility of bool // dxf 60
    | Color of int // dxf 62
    | Text of string // dxf 1
    | LineTypeName of string // dxf 6
    | TextStyleName of string // dxf 7
    | TxtSize of double // dxf 40
    | RegApp of string // dxf -3
    | Dxf of int * Object // 组码

    /// 比较
    | Comp of int * string * Object // dxf -4
    | Or of OpFilter list // <OR   ... OR>
    | And of OpFilter list // <AND   ... AND>
    | Not of OpFilter // <NOT   ... NOT>
    | Xor of OpFilter * OpFilter // <XOR   ... XOR>
    
    /// and
    static member (&&&)(v1: OpFilter, v2) = And [ v1; v2 ]
    /// or
    static member (|||)(v1: OpFilter, v2) = Or [ v1; v2 ]
    /// not
    static member (!)(v1: OpFilter) = Not v1
    
    /// 构建过滤器
    member __.build() =

        let rec loop filter =
            match filter with
            | Comp(i, op, obj) -> [ TypedValue(-4, op); TypedValue(i, obj) ]
            | And a ->
                let tmp = a |> List.map loop |> List.collect id
                [ TypedValue(-4, "<and") ] @ tmp @ [ TypedValue(-4, "and>") ]
            | Or a ->
                let tmp = a |> List.map loop |> List.collect id
                [ TypedValue(-4, "<or") ] @ tmp @ [ TypedValue(-4, "or>") ]
            | Not a ->
                let tmp = loop a
                [ TypedValue(-4, "<not") ] @ tmp @ [ TypedValue(-4, "not>") ]
            | Xor(a, b) -> [ TypedValue(-4, "<xor") ] @ loop a @ loop b @ [ TypedValue(-4, "xor>") ]
            | EntityType typename -> [ TypedValue(0, typename) ]
            | BlockName name -> [ TypedValue(2, name) ]
            | LayerName name -> [ TypedValue(8, name) ]
            | Visibility vis -> [ TypedValue(60, vis) ]
            | Color color -> [ TypedValue(62, color) ]
            | Text text -> [ TypedValue(1, text) ]
            | LineTypeName name -> [ TypedValue(6, name) ]
            | TextStyleName name -> [ TypedValue(7, name) ]
            | TxtSize size -> [ TypedValue(40, size) ]
            | RegApp app -> [ TypedValue(-3, app) ]
            | Dxf(i, v) -> [ TypedValue(i, v) ]

        loop __

/// 过滤器函数模块
[<AutoOpen>]
module OpFilter =
    /// <summary>
    /// 选择集
    /// </summary>
    /// <param name="message">提示</param>
    /// <param name="filter">过滤器</param>
    /// <returns>id集合</returns>
    let ssget message (filter: OpFilter) =
        let opt = PromptSelectionOptions()
        opt.MessageForAdding <- message
        let filter = SelectionFilter(filter.build () |> Array.ofList)
        let res =
            AcCoreApp.DocumentManager.MdiActiveDocument.Editor.GetSelection filter

        if res.Status = PromptStatus.OK then
            res.Value.GetObjectIds() |> List.ofArray
        else
            []
    
    /// <summary>
    /// 窗选选择集
    /// </summary>
    /// <param name="pt1">左下角坐标</param>
    /// <param name="pt2">右上角坐标</param>
    /// <param name="filter">过滤器</param>
    /// <returns>id集合</returns>
    let ssgetw pt1 pt2 (filter: OpFilter) =
        let filter = SelectionFilter(filter.build () |> Array.ofList)
        let res = AcCoreApp.DocumentManager.MdiActiveDocument.Editor
                      .SelectWindow(pt1, pt2, filter)

        if res.Status = PromptStatus.OK then
            res.Value.GetObjectIds() |> List.ofArray
        else
            []

    /// <summary>
    /// 拦选选择集
    /// </summary>
    /// <param name="pt1">左下角坐标</param>
    /// <param name="pt2">右上角坐标</param>
    /// <param name="filter">过滤器</param>
    /// <returns>id集合</returns>
    let ssgetc pt1 pt2 (filter: OpFilter) =

        let filter = filter.build () |> Array.ofList |> SelectionFilter

        let res = AcCoreApp.DocumentManager.MdiActiveDocument.Editor
                      .SelectCrossingWindow(pt1, pt2, filter)

        if res.Status = PromptStatus.OK then
            res.Value.GetObjectIds() |> List.ofArray
        else
            []
    
    /// <summary>
    /// 多边形窗选
    /// </summary>
    /// <param name="pts">点集</param>
    /// <param name="filter">过滤器</param>
    /// <returns>id集合</returns>
    let ssgetwp pts (filter: OpFilter) =
        let filter = SelectionFilter(filter.build () |> Array.ofList)

        let res =
            AcCoreApp.DocumentManager.MdiActiveDocument.Editor
                .SelectWindowPolygon(new Point3dCollection(pts |> Array.ofList), filter)

        if res.Status = PromptStatus.OK then
            res.Value.GetObjectIds() |> List.ofArray
        else
            []

    /// <summary>
    /// 多边形拦选
    /// </summary>
    /// <param name="pts">点集</param>
    /// <param name="filter">过滤器</param>
    /// <returns>id集合</returns>
    let ssgetcp pts (filter: OpFilter) =
        let filter = SelectionFilter(filter.build () |> Array.ofList)

        let res =
            AcCoreApp.DocumentManager.MdiActiveDocument.Editor
                .SelectCrossingPolygon(new Point3dCollection(pts |> Array.ofList), filter)

        if res.Status = PromptStatus.OK then
            res.Value.GetObjectIds() |> List.ofArray
        else
            []
